package com.ilongsay.service.impl;

import com.ilongsay.dao.BillSqliteDao;
import com.ilongsay.dao.BillSqliteDetailDao;
import com.ilongsay.entity.AjaxObject;
import com.ilongsay.entity.ChaiFenSetting;
import com.ilongsay.entity.FaPiao;
import com.ilongsay.entity.FaPiaoDetail;
import com.ilongsay.service.ISplitService;
import com.ilongsay.utils.CalcUtils;
import com.ilongsay.utils.ConfirmUtils;
import com.ilongsay.utils.DateUtils;
import com.ilongsay.utils.UuidUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * @Author ilongsay
 * @Email ilongsay@163.com
 * @Copyright 版本所有，侵权必究！
 * @Datetime 2018-12-26 13:00
 * @Describution 这里的服务以后肯定是要拆分为分布式
 */
@Service("splitService")
public class SplitServiceImpl implements ISplitService {
    //TODO:需整合到配置文件中
    private static final String MSG_OK = "拆分成功，请检查数据是否正确！";
    @Autowired
    private BillSqliteDao billSqliteDao;

    @Autowired
    private BillSqliteDetailDao billSqliteDetailDao;

    @Autowired
    private AjaxObject ajaxObject;

    /**
     * @param chaiFenSetting
     * @return com.ilongsay.entity.AjaxObject
     * 按明细进行拆分
     */
    @Override
    public AjaxObject splitByMX(ChaiFenSetting chaiFenSetting) throws InvocationTargetException, IllegalAccessException {

        String[] split = chaiFenSetting.getBillCode().split("\\,");
        //AjaxObject ajaxObject = new AjaxObject();
        String date = DateUtils.date().substring(8);

        List<String> list;
        //TODO：这里的时间需要改正一下
        String s = split[0] + "CF" + date;
        String[] billCodeDetails = chaiFenSetting.getBillCodeDetail().split("\\,");

        //根据传进来的订单信息查询本地数据库的主表数据，有且仅有一条数据
        List<FaPiao> faPiaos = null;
        try {
            faPiaos = billSqliteDao.findBillByBillCode(split[0]);
        } catch (Exception e) {
            ajaxObject.setCode("1");
            e.printStackTrace();
            ajaxObject.setMsg("查询数据为空" + e.toString());
            return ajaxObject;
        }
        FaPiao faPiao = new FaPiao();
        BeanUtils.copyProperties(faPiao,faPiaos.get(0));//克隆一份对象

        //在主表中插入多一条主表数据，名字为主表的订单号+CF
        faPiao.setBillCode(s);
        //设置拆分的id
        faPiao.setUid(UuidUtils.randomString());

        String total = "0";
        String untotal = "0";
        String taxAmount = "0";
        list = new ArrayList<>();
        //遍历所有的明细，TODO:看下需不需要优化，先实现功能，实现拆分后的发票数据汇总
//        for (String billCodeDetail : billCodeDetails) {
//            list.add(billCodeDetail);//存储明细的id号
//            for (FaPiaoDetail faPiaoDetail : faPiao.getFaPiaoDetails()) {
//                if (faPiaoDetail.getUpid().equals(billCodeDetail)) {
//                    taxAmount = CalcUtils.add(faPiaoDetail.getTaxAmount(), taxAmount);
//                    untotal = CalcUtils.add(faPiaoDetail.getUntotal(), untotal);
//                    total = CalcUtils.add(faPiaoDetail.getTotal(), total);
//                }
//            }
//        }
        //优化后的版本，小循环在内，大循环在外，仅需要遍历1次明细即可
        for (FaPiaoDetail faPiaoDetail : faPiao.getFaPiaoDetails()) {
            for (String billCodeDetail : billCodeDetails) {
                list.add(billCodeDetail);//存储明细的id号
                if (faPiaoDetail.getUpid().equals(billCodeDetail)) {
                    taxAmount = CalcUtils.add(faPiaoDetail.getTaxAmount(), taxAmount);
                    untotal = CalcUtils.add(faPiaoDetail.getUntotal(), untotal);
                    total = CalcUtils.add(faPiaoDetail.getTotal(), total);
                }
            }
        }


        faPiao.setTotal(total);
        faPiao.setUntotal(untotal);
        faPiao.setTaxAmount(taxAmount);

        faPiaos.get(0).setTotal(CalcUtils.sub(faPiaos.get(0).getTotal(), total));//剩下的金额=原始金额-拆分金额
        faPiaos.get(0).setTaxAmount(CalcUtils.sub(faPiaos.get(0).getTaxAmount(), taxAmount));
        faPiaos.get(0).setUntotal(CalcUtils.sub(faPiaos.get(0).getUntotal(), untotal));

        billSqliteDao.updateAll(faPiaos.get(0));//更新值

        List<FaPiao> fapiao = new ArrayList<>();
        fapiao.add(faPiao);
        try {
            //将数据插入到主表中
            billSqliteDao.insertBill(fapiao);
        } catch (Exception e) {
            ajaxObject.setCode("1");
            e.printStackTrace();
            ajaxObject.setMsg("数据插入本地主表失败！" + e.toString());
            return ajaxObject;
        }
        try {
            billSqliteDetailDao.updateByIds(list, s);//将选中的id传入
        } catch (Exception e) {
            ajaxObject.setCode("1");
            e.printStackTrace();
            ajaxObject.setMsg("更新明细表失败！" + e.toString());
            return ajaxObject;
        }
        ajaxObject.setCode("0");
        ajaxObject.setMsg(MSG_OK);
        return ajaxObject;
    }

    /**
     * @param chaiFenSetting 拆分设置
     * @return java.lang.Object
     * 按税率拆分单据
     */
    @Override
    public AjaxObject splitByTaxRate(ChaiFenSetting chaiFenSetting) {
        String[] split = chaiFenSetting.getBillCode().split("\\,");
        //AjaxObject ajaxObject = new AjaxObject();
        for (String billCode : split) {
            //int i = 0;
            //查询主表只有一条数据
            List<FaPiao> faPiaos = null;
            try {
                faPiaos = billSqliteDao.findBillByBillCode(billCode);
            } catch (Exception e) {
                ajaxObject.setCode("1");
                e.printStackTrace();
                ajaxObject.setMsg("查询主表数据失败，请输入正确的单号！" + e.toString());
                return ajaxObject;
            }

            List<FaPiaoDetail> billCodes = null;
            //明细表数据
            billCodes = faPiaos.get(0).getFaPiaoDetails();

            //这里对税率进行过滤，利用map的key不能重复的特点（基于set），也可以存set中
            Map<String, String> map = new HashMap<>();
            for (FaPiaoDetail faPiaoDetail : billCodes) {
                map.put(faPiaoDetail.getTaxRate(), faPiaoDetail.getTaxRate());
            }

            for (String taxRate : map.keySet()) {
                //i++;//每遍历一次i就+1，用来区分拆分单据，因为后缀是按税率，这里暂时取消
                String bill = billCode + "CF" + taxRate;//拆分的后缀用税率表示，因为是按税率进行拆分的！
                faPiaos.get(0).setBillCode(bill);//遍历一次就设置一次拆分后的订单号码\
                faPiaos.get(0).setUid(UuidUtils.randomString());//设置单据的id

                String taxAmount = "0";
                String total = "0";
                String untotal = "0";
                //计算出每一条明细的汇总金额和未税金额
                for (FaPiaoDetail faPiaoDetail : billCodes) {
                    if (faPiaoDetail.getTaxRate().equals(taxRate)) {
                        taxAmount = CalcUtils.add(faPiaoDetail.getTaxAmount(), taxAmount);
                        total = CalcUtils.add(faPiaoDetail.getTotal(), total);
                        untotal = CalcUtils.add(faPiaoDetail.getUntotal(), untotal);
                    }
                }
                faPiaos.get(0).setTaxAmount(taxAmount);
                faPiaos.get(0).setUntotal(untotal);
                faPiaos.get(0).setTotal(total);
                ConfirmUtils.mergeNodes(faPiaos,true);
                try {
                    billSqliteDao.insertBill(faPiaos);//将新得到的拆分后的单据插入到主表数据中
                } catch (Exception e) {
                    ajaxObject.setCode("1");
                    e.printStackTrace();
                    ajaxObject.setMsg("插入主表的数据失败！" + e.toString());
                    return ajaxObject;
                }
                try {
                    billSqliteDetailDao.updateByTaxRates(taxRate, bill, billCode);//按税率更新
                } catch (Exception e) {
                    ajaxObject.setCode("1");
                    e.printStackTrace();
                    ajaxObject.setMsg("更新明细信息失败" + e.toString());
                    return ajaxObject;
                }
            }
            try {
                //删除原始的单据号，不是选择明细的拆分，不留原始单号！
                billSqliteDao.deleteBillByBillCode(billCode);
            } catch (Exception e) {
                ajaxObject.setCode("1");
                e.printStackTrace();
                ajaxObject.setMsg("删除原始单号失败！" + e.toString());
                return ajaxObject;
            }
        }
        ajaxObject.setCode("0");
        ajaxObject.setMsg(MSG_OK);
        return ajaxObject;
    }

    /**
     * @param chaiFenSetting 拆分设置
     * @return com.ilongsay.entity.AjaxObject
     * 按客户输入的金额拆分
     * 还有一些bug，比如会出现0E-8的情况:bug已经解决
     * 2019-01-01:出现新bug，新增了一些字段导致按金额拆分不能实现
     */
    @Override
    public AjaxObject splitByAmount(ChaiFenSetting chaiFenSetting) throws InvocationTargetException, IllegalAccessException {
        //AjaxObject ajaxObject = new AjaxObject();
        String[] split = chaiFenSetting.getBillCode().split("\\,");
        //将传进来的数据的空格过滤掉
        chaiFenSetting.getAmount().replace(" ", "");

        //如果金额不为0，或者是金额都为空
        if (!chaiFenSetting.getAmount().equals("") && !chaiFenSetting.getAmount().equals("0")) {
            for (String billCode : split) {

                //查询主表只有一条数据
                List<FaPiao> faPiaos = billSqliteDao.findBillByBillCode(billCode);

                //根据单号查询明细订单表
                List<FaPiaoDetail> billCodes = faPiaos.get(0).getFaPiaoDetails();

                String totalAmount = "0";//求出的总金额
                double amount;

                try {
                    amount = Double.valueOf(chaiFenSetting.getAmount());//用户传进来的拆分金额);
                } catch (Exception e) {
                    ajaxObject.setCode("1");
                    e.printStackTrace();
                    ajaxObject.setMsg("设置的金额格式有误，请检查是否有其他字符串！" + e.toString());
                    return ajaxObject;
                }

                //得到明细的全部金额,判断拆分金额的类型，1含税，0不含税
                if (chaiFenSetting.getIsTax().equals("1")) {
                    totalAmount = faPiaos.get(0).getTotal();
                }else if (chaiFenSetting.getIsTax().equals("0")){
                    totalAmount = faPiaos.get(0).getUntotal();
                }

                int q = Double.valueOf(totalAmount).intValue();
                int m = q % (int)amount == 0 ? q / (int)amount : q / (int)amount + 1;//拆分后单据的数量

                List<List<FaPiaoDetail>> list1 = new LinkedList<>();

                String getAmount = "0";//得到汇总金额
                int loop2 = 0;
                //制定循环的次数，能拆分多少单据便循环多少次
                for (int i = 0; i < m; i++) {
                    List<FaPiaoDetail> list = new LinkedList<>();

                    loop2:
                    for (int j = loop2; j < billCodes.size(); j++) {//遍历明细表的单据
                        loop2++;
                        FaPiaoDetail faPiaoDetail = billCodes.get(j);

                        //判断是否含税分别赋值
                        if (chaiFenSetting.getIsTax().equals("1")) {
                            getAmount = CalcUtils.add(faPiaoDetail.getTotal(), getAmount);
                        }else if (chaiFenSetting.getIsTax().equals("0")){
                            getAmount = CalcUtils.add(faPiaoDetail.getUntotal(), getAmount);
                        }

                        //如果当前明细的汇总金额小于设置的金额，就将当前的明细增加到list中
                        if (Double.valueOf(getAmount) <= amount) {
                            list.add(faPiaoDetail);

                          //如果当前明细的金额大于设置金额，将明细的部分数据插入到新的list中
                        } else if (Double.valueOf(getAmount) > amount) {
                            String n = "0";
                            if (chaiFenSetting.getIsTax().equals("1")) {
                                //剩下的金额 = 设置金额-（明细汇总金额-当前明细的金额）
                                n = CalcUtils.sub(chaiFenSetting.getAmount(),
                                        CalcUtils.sub(getAmount, faPiaoDetail.getTotal()));
                            }else if (chaiFenSetting.getIsTax().equals("0")){
                                //剩下的金额 = 设置金额-（明细汇总金额-当前明细的金额）
                                n = CalcUtils.sub(chaiFenSetting.getAmount(),
                                        CalcUtils.sub(getAmount, faPiaoDetail.getUntotal()));
                            }

                            //解决了拆分单据会出现的0E-8的现象，总金额只能保留2位小数
                            if (!n.equals("0")&& CalcUtils.round(n,2)!=0) {
                                FaPiaoDetail faPiaoDetail2 = new FaPiaoDetail();
                                //克隆一份对象，不然修改会改变list的引用的值
                                BeanUtils.copyProperties(faPiaoDetail2, faPiaoDetail);

                                if (chaiFenSetting.getIsTax().equals("1")) {
                                    faPiaoDetail2.setTotal(CalcUtils.sround(n,2));
                                    //未税金额 = 含税金额÷（1+税率）保留2位小数
                                    faPiaoDetail2.setUntotal(CalcUtils.div(faPiaoDetail2.getTotal(),
                                            CalcUtils.add("1",faPiaoDetail2.getTaxRate()),2));
                                    //设置税额 = 含税金额-未税金额
                                    faPiaoDetail2.setTaxAmount(CalcUtils.sub(faPiaoDetail2.getTotal(),faPiaoDetail2.getUntotal()));

                                    //剩下的数量，默认保留8位小数，使用含税金额拆分就是默认使用含税金额÷含税单价
                                    faPiaoDetail2.setQuantity(CalcUtils.div(faPiaoDetail2.getUntotal(), faPiaoDetail2.getUntPrice(), 8));
                                    list.add(faPiaoDetail2);

                                    //剩下的含税金额 = 当前金额 - n  TODO:这里日后需要优化，变成含税单价
                                    faPiaoDetail.setTotal(CalcUtils.sub(faPiaoDetail.getTotal(), n));

                                    //未税金额 = 原来的金额 - 拆分后的未税金额（防止有0.01分的误差出现）
                                    faPiaoDetail.setUntotal(CalcUtils.sub(faPiaoDetail.getUntotal(), faPiaoDetail2.getUntotal()));

                                    //税额 = 原来的税额 - 拆分后的税额
                                    faPiaoDetail.setTaxAmount(CalcUtils.sub(faPiaoDetail.getTaxAmount(),faPiaoDetail2.getTaxAmount()));

                                    //剩下的数量：原始单据的数量 - 拆分单据数量
                                    faPiaoDetail.setQuantity(CalcUtils.sub(faPiaoDetail.getQuantity(),faPiaoDetail2.getQuantity()));
                                }else if (chaiFenSetting.getIsTax().equals("0")){
                                    //设置n的未税金额，保留2位小数
                                    faPiaoDetail2.setUntotal(CalcUtils.sround(n,2));
                                    //含税金额 = 未税金额*(1+税率)，保留2位小数
                                    faPiaoDetail2.setTotal(CalcUtils.sround(
                                                           CalcUtils.mul(faPiaoDetail2.getUntotal(),
                                                           CalcUtils.add("1",faPiaoDetail2.getTaxRate())),2));
                                    //设置税额 = 含税金额-未税金额
                                    faPiaoDetail2.setTaxAmount(CalcUtils.sub(faPiaoDetail2.getTotal(),faPiaoDetail2.getUntotal()));
                                    //设置数量
                                    faPiaoDetail2.setQuantity(CalcUtils.div(faPiaoDetail2.getUntotal(), faPiaoDetail2.getUntPrice(), 8));
                                    list.add(faPiaoDetail2);

                                    //剩下的未税金额 = 当前金额 - n
                                    faPiaoDetail.setUntotal(CalcUtils.sub(faPiaoDetail.getUntotal(), n));

                                    //含税金额 = 原来的含税金额 - 拆分后的含税金额（防止有0.01分的误差出现）
                                    faPiaoDetail.setTotal(CalcUtils.sub(faPiaoDetail.getTotal(), faPiaoDetail2.getTotal()));

                                    //税额 = 原来的税额 - 拆分后的税额
                                    faPiaoDetail.setTaxAmount(CalcUtils.sub(faPiaoDetail.getTaxAmount(),faPiaoDetail2.getTaxAmount()));

                                    //剩下的数量：原始单据的数量 - 拆分单据数量
                                    faPiaoDetail.setQuantity(CalcUtils.sub(faPiaoDetail.getQuantity(),faPiaoDetail2.getQuantity()));
                                }
                            }
                            getAmount = "0";
                            loop2--;
                            break loop2;
                        }
                    }
                    //将得到的list集合插入到list中
                    list1.add(list);
                }

                //将符合数据的数据插入到明细表中
                for (List<FaPiaoDetail> list : list1) {
                    try {
                        billSqliteDao.deleteBillByBillCode(billCode);//将主表的原始单号删除
                        billSqliteDetailDao.deleteBillDetailsByBillCode(billCode);//将明细表的原始的数据删除
                    } catch (Exception e) {
                        ajaxObject.setCode("1");
                        e.printStackTrace();
                        ajaxObject.setMsg("删除主表或明细表数据错误！" + e.toString());
                        return ajaxObject;
                    }

                    //设置主表的订单号码
                    StringBuilder string = new StringBuilder();
                    string.append(billCode).append("000").append(String.valueOf(m));
                    faPiaos.get(0).setBillCode(string.toString());
                    faPiaos.get(0).setUid(UuidUtils.randomString());//设置主表的uuid
                    //设置明细表的订单编号
                    for (FaPiaoDetail faPiaoDetail : list) {
                        faPiaoDetail.setBillCode(string.toString());
                        faPiaoDetail.setUpid(UuidUtils.randomString());
                    }
                    faPiaos.get(0).setFaPiaoDetails(list);

                    //校验数据的正确性，设置汇总主表的金额税额之类的信息
                    ConfirmUtils.confirmAmount(faPiaos.get(0),chaiFenSetting);
                    ConfirmUtils.mergeNodes(faPiaos,true);//这里需要查找设置里面的设置
                    //XXX:注意：sqlite不支持联合插入数据库，因此只能分开插入数据库
                    try {
                        billSqliteDao.insertBill(faPiaos);//将主表插入到数据库中
                    } catch (Exception e) {
                        ajaxObject.setCode("1");
                        e.printStackTrace();
                        ajaxObject.setMsg("插入主表失败" + e.toString());
                        return ajaxObject;
                    }
                    try {
                        billSqliteDetailDao.insertBillDetail(list);//再将明细插入到数据库中
                    } catch (Exception e) {
                        ajaxObject.setCode("1");
                        e.printStackTrace();
                        ajaxObject.setMsg("插入明细表失败！" + e.toString());
                        return ajaxObject;
                    }
                    m--;
                }
            }
        }else {
            ajaxObject.setCode("1");
            ajaxObject.setMsg("数据为空或者设置为0，请检查设置金额！");
            return ajaxObject;
        }
        ajaxObject.setCode("0");
        ajaxObject.setMsg(MSG_OK);
        return ajaxObject;
    }
}
